package io.jsen.meta.diff.context;

import com.google.common.reflect.TypeToken;
import io.jsen.meta.diff.field.MetaFieldDefine;
import io.jsen.meta.diff.obj.Convert;
import io.jsen.meta.diff.obj.MetaObject;
import io.jsen.meta.diff.support.MetaDiffModel;

/**
 * facade
 * <p>
 * 入口参考
 * {@link MetaContext}
 * <p>
 * {@link io.jsen.meta.diff.feature.MetaFeatureContext}
 * <p>
 * {@link MetaFieldDefineContext}
 * <p>
 *
 * @author jsen
 * @date 2021/4/7
 */
public class MetaContext {

    static {
        DefaultMetaConvertInit.register();
    }

    /**
     * native对象diff，diff后是一个meta对象，newObj和oldObj类型必须一致
     *
     * @param metaDiffModel metaDiffModel
     * @return res
     */
    @SuppressWarnings("rawtypes")
    public static <T> MetaObject toMeta(MetaDiffModel<T> metaDiffModel) {
        MetaFieldDefineContext.register(metaDiffModel.getToken());
        return MetaOpContext.toMeta(metaDiffModel);
    }

    /**
     * 加载一个diff对象
     *
     * @param typeToken typeToken
     * @param nativeObj nativeObj
     * @return res
     */
    @SuppressWarnings("all")
    public static <T> MetaObject loadMeta(TypeToken<T> typeToken, T nativeObj) {
        MetaFieldDefineContext.register(typeToken);
        return MetaOpContext.loadMeta(typeToken, nativeObj);
    }

    /**
     * diff对象转为native object
     * <p>
     * native对象是变更后所有有变更的
     *
     * @param metaObject metaObject
     * @return res
     */
    @SuppressWarnings("unchecked")
    public static <T> T toNative(MetaObject<?, ?> metaObject) {
        return (T) MetaOpContext.toNative(metaObject);
    }


    /**
     * 注册字段转换器
     *
     * @param clazz   nativeClass / metaObjectClass
     * @param convert convert
     * @param <S>     in type
     * @param <T>     out type
     */
    public static <S, T> void registerConvert(Class<?> clazz, Convert<S, T> convert) {
        MetaObjectConvertContext.register(clazz, convert);
    }


    /**
     * 注册某个字段的默认删除字段
     * <p>
     * 比如某个类的某个字段 -1L 代表删除
     *
     * @param field field
     * @param val   val
     */
    public static void registerFieldDelete(MetaFieldDefine field, Object val) {
        MetaDeleteContext.registerFieldDelete(field, val);
    }

    /**
     * 注册某个类的默认删除字段
     * <p>
     * 比如Long -1L 代表删除
     *
     * @param clazz clazz
     * @param val   val
     */
    public static void registerTypeDelete(MetaFieldDefine clazz, Object val) {
        MetaDeleteContext.registerTypeDelete(clazz, val);
    }

    private MetaContext() {
    }
}
